//
//  Enum.swift
//  cnswift-demo
//
//  Created by YangWei on 2020/12/28.
//  Copyright © 2020 YangWei. All rights reserved.
//

import UIKit

class Enumerations: SWDBaseObject {
    
    class func run() {
        
        let enumerations = Enumerations()
        
        // 2 枚举语法
        enumerations.enumerationSyntax()
        
        // 3 使用 Switch 语句来匹配枚举值
        enumerations.matchingEnumerationValuesWithASwitchStatement()
        
        // 4 遍历枚举情况（case）
        enumerations.iteratingOverEnumerationCases()
        
        // 5 关联值
        enumerations.associatedValues()
        
        // 6 原始值
        enumerations.rawValues()
        
        // 6.1 隐式指定的原始值
        enumerations.implicitlyAssignedRawValues()
        
        // 6.2
        enumerations.initializingFromARawValue()
        
        // 7
        enumerations.recursiveEnumerations()
    }
    
    /// 2 枚举语法
    func enumerationSyntax() {
        let title = "2 枚举语法";
        printStartLine(title)
        
        var directionToHead = CompassPoint.west
        print(directionToHead) // west
        
        directionToHead = .east
        print(directionToHead) // east
        
        printEndLine(title)
    }
    
    /// 2 枚举语法
    /// 指南针的四个主要方向
    enum CompassPoint {
        case north
        case south
        case east
        case west
    }
    
    /// 3 使用 Switch 语句来匹配枚举值
    func matchingEnumerationValuesWithASwitchStatement() {
        let title = "3 使用 Switch 语句来匹配枚举值";
        printStartLine(title)
        
        let directionToHead = CompassPoint.south
        
        /* 用 switch 语句来匹配每一个单独的枚举值 */
        switch directionToHead {
        case .north:
            print("许多行星都有一个北极")
        case .south:
            print("小心企鹅")
        case .east:
            print("太阳升起的地方")
        case .west:
            print("那里的天空是蓝色的")
        }
        // 小心企鹅
        
        /* 使用 default 包含那些省略的成员 case */
        let somePlanet = Planet.earth
        switch somePlanet {
        case .earth:
            print("基本无害")
        default:
            print("对人类来说不是一个安全的地方")
        }
        // 基本无害
        
        printEndLine(title)
    }
    
    /// 3 使用 Switch 语句来匹配枚举值
    /// 行星
    enum Planet {
        // 多个成员值可以在同一行中，用逗号隔开
        /* 八大行星： 水星、金星、地球、火星、木星、土星、天王星、海王星 */
        case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
    }
    
    /// 4 遍历枚举情况（case）
    func iteratingOverEnumerationCases() {
        let title = "4 遍历枚举情况（case）";
        printStartLine(title)
        
        let numberOfChoices = Beverage.allCases.count
        print("供应\(numberOfChoices)种饮料")
        // 供应3种饮料
        
        /** 测试：不加 CaseIterable 会报错
         let numerOfPlanets = Planet.allCases.count
         print("一共\(numerOfPlanets)大行星")
         */
        
        /* 用 for 循环遍历 allCase：*/
        for beverage in Beverage.allCases {
            print(beverage)
        }
        // coffee
        // tea
        // juice
        
        printEndLine(title)
    }
    
    /// 4 遍历枚举情况（case）
    /// 饮料
    enum Beverage: CaseIterable {
        // 咖啡，茶，果汁
        case coffee, tea, juice
    }
    
    /// 5 关联值
    func associatedValues() {
        let title = "5 关联值";
        printStartLine(title)
        
        var productBarcode = Barcode.upc(8, 85909, 51226, 3)
        print(productBarcode)
        productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
        print(productBarcode)
        
        switch productBarcode {
        case .upc(let numberSystem, let manufacturer, let product, let check):
            print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
        case .qrCode(let productCode):
            print("QR code: \(productCode).")
        }
        // QR code: ABCDEFGHIJKLMNOP.
        
        /* 提取同样的 let 或 var 放置在前面 */
        switch productBarcode {
        case let .upc(numberSystem, manufacturer, product, check):
            print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
        case let .qrCode(productCode):
            print("QR code: \(productCode).")
        }
        // QR code: ABCDEFGHIJKLMNOP.
        
        printEndLine(title)
    }
    
    /// 5 关联值
    /// 条形码
    enum Barcode {
        case upc(Int, Int, Int, Int)
        case qrCode(String)
    }
    
    /// 6 原始值
    func rawValues() {
        let title = "6 原始值";
        printStartLine(title)
        
        let rawValue = ASCIIControlCharacter.tab
        print(rawValue.rawValue) // \t 空白行看不到
        
        printEndLine(title)
    }
    
    /// 6 原始值
    /// ASC 码控制字符
    enum ASCIIControlCharacter: Character {
        case tab = "\t"
        case lineFeed = "\n"
        case carriageReturn = "\r"
    }
    
    /// 6.1 隐式指定的原始值
    func implicitlyAssignedRawValues() {
        let title = "6.1 隐式指定的原始值";
        printStartLine(title)
        
        let earthsOrder = PlanetV2.earth.rawValue
        print(earthsOrder)
        // 3
         
        let sunsetDirection = CompassPointV2.west.rawValue
        print(sunsetDirection)
        // west
        
        printEndLine(title)
    }
    
    /// 6.1 隐式指定的原始值
    /// 行星（原始值为整数）
    enum PlanetV2: Int {
        /* 八大行星： 水星、金星、地球、火星、木星、土星、天王星、海王星 */
        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    }
    
    /// 6.1 隐式指定的原始值
    /// 指南针的四个主要方向（原始值为字符串）
    enum CompassPointV2: String {
        case north
        case south
        case east
        case west
    }
    
    /// 6.2 从原始值初始化
    func initializingFromARawValue() {
        let title = "6.2 从原始值初始化";
        printStartLine(title)
        
        let possiblePlanet = PlanetV2(rawValue: 7)
        print(possiblePlanet as Any)
        // Optional(cnswift_demo.PlanetV2.uranus)
        
        /* 原始值初始化器是一个可失败初始化器，不是所有原始值都将返回一个枚举成员 */
        let positionToFind = 11
        if let somePlanet = PlanetV2(rawValue: positionToFind) {
            switch somePlanet {
            case .earth:
                print("基本无害")
            default:
                print("对人类来说不是一个安全的地方")
            }
        } else {
            print("这个位置 \(positionToFind) 上没有行星")
        }
        // 这个位置 11 上没有行星
        
        printEndLine(title)
    }
    
    /// 7 递归枚举
    func recursiveEnumerations() {
        let title = "7 递归枚举";
        printStartLine(title)
        
        /* (5 + 4) * 2 */
        let five = ArithmeticExpression.number(5)
        print(five)

        let four = ArithmeticExpression.number(4)
        print(four)

        let sum = ArithmeticExpression.addition(five, four)
        print(sum)

        let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
        print(product)
        
        /* 一个判断数学表达式的函数 */
        func evaluate(_ expression: ArithmeticExpression) -> Int {
            switch expression {
            case let .number(value):
                return value
            case let .addition(left, right):
                return evaluate(left) + evaluate(right)
            case let .multiplication(left, right):
                return evaluate(left) * evaluate(right)
            }
        }
         
        print(evaluate(product))
        // 18
        
        printEndLine(title)
    }
    
    /// 7 递归枚举
    /// 数学表达式
    enum ArithmeticExpression {
        case number(Int)
        // indirect 表示支持递归
        indirect case addition(ArithmeticExpression, ArithmeticExpression)
        indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
    }
    
    /// 7 递归枚举
    /// 数学表达式（整个支持递归，另一种写法）
    indirect enum ArithmeticExpressionV2 {
        case number(Int)
        case addition(ArithmeticExpressionV2, ArithmeticExpressionV2)
        case multiplication(ArithmeticExpressionV2, ArithmeticExpressionV2)
    }
}
